﻿using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Infrastructure.Extensions;
using Infrastructure.Model.UserAuth;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;

namespace Infrastructure.Helper
{
    public class JwtUtil
    {
        /// <summary>
        /// 用于签名 JWT 的密钥（对称加密密钥）。
        /// </summary>
        public static readonly string KEY = "this-is-a-32-character-long-secret-key-123456";
        /// <summary>
        /// 从 HTTP 请求头解析 JWT，返回登录用户信息（无缓存版本）。
        /// </summary>
        public static LoginUser GetLoginUser(HttpContext httpContext)
        {
            // 双重兼容读取
            string token = httpContext.ReadHeader("Authorization")
                        ?? httpContext.ReadHeader("auth_token");
            if (!string.IsNullOrEmpty(token))
            {
                // 解析并验证 Token
                IEnumerable<Claim> claims = ParseToken(token);
               
                LoginUser loginUser = ValidateJwtToken(claims);
                if (loginUser != null)
                {
                    loginUser.Token = token; // 可选：附加原始 Token
                    return loginUser;
                }
            }
            return null;
        }
        /// <summary>
        /// 从 HTTP 上下文中获取 JWT 并返回对应的登录用户信息。
        /// </summary>
        /// <param name="httpContext">HTTP 上下文，包含请求信息。</param>
        /// <param name="distributedCache">分布式缓存实例，用于存储/获取 Token。</param>
        /// <returns>返回登录用户信息，如果没有 JWT 或解析失败则返回 null。</returns>
        public static LoginUser GetLoginUser(HttpContext httpContext, IDistributedCache distributedCache)
        {
            // 从 HTTP 上下文的分布式缓存中获取 JWT Token
            string token = httpContext.GetToken(distributedCache);
            if (!string.IsNullOrEmpty(token))
            {
                // 解析并验证 Token，获取登录用户信息
                IEnumerable<Claim> claims = ParseToken(token);
                LoginUser loginUser = ValidateJwtToken(claims);
                if (loginUser != null)
                {
                    // 将原始 Token 附加到用户对象（非必要，视业务需求）
                    loginUser.Token = token;
                    return loginUser;
                }
            }

            // 未找到有效 Token 或解析失败
            return null;
        }

        /// <summary>
        /// 根据用户的 Claims 生成 JWT Token。
        /// </summary>
        /// <param name="claims">用户的 Claims 集合。</param>
        /// <returns>返回生成的 JWT Token 字符串。</returns>
        public static string GenerateJwtToken(List<Claim> claims)
        {
            // 初始化 JWT 处理器
            JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
            // 将密钥字符串转换为字节数组（ASCII 编码）
            byte[] keyBytes = Encoding.ASCII.GetBytes(KEY);

            // 配置 Token 描述，包括声明、有效期和签名凭证
            SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims), // 设置 Token 的主体（Claims）
                Expires = DateTime.Now.AddYears(1), // 设置 Token 过期时间为 1 年后
                SigningCredentials = new SigningCredentials(
                    new SymmetricSecurityKey(keyBytes), // 使用对称密钥签名
                    "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256") // HMAC-SHA256 算法标识符
            };

            // 创建并写入 Token
            SecurityToken token = jwtSecurityTokenHandler.CreateToken(tokenDescriptor);
            return jwtSecurityTokenHandler.WriteToken(token);
        }

        /// <summary>
        /// 解析并验证 JWT Token，返回其中的 Claims 信息。
        /// </summary>
        /// <param name="token">待解析的 JWT 字符串。</param>
        /// <returns>返回 Token 中的 Claims，验证失败则返回 null。</returns>
        public static IEnumerable<Claim> ParseToken(string token)
        {
            // 移除可能的"Bearer "前缀
            if (!string.IsNullOrEmpty(token) && token.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
            {
                token = token.Substring(7).Trim();
            }

            var handler = new JwtSecurityTokenHandler();
            var keyBytes = Encoding.ASCII.GetBytes(KEY);

            try
            {
                // 创建验证参数 - 使用新版本API
                var validationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(keyBytes),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ClockSkew = TimeSpan.Zero,

                    // 新版本中禁用声明映射的正确方式
                    NameClaimType = "unique_name", // 明确指定名称声明类型
                    RoleClaimType = "role"         // 明确指定角色声明类型
                };

                // 禁用声明映射（新版本方式）
                handler.InboundClaimTypeMap.Clear();
                handler.OutboundClaimTypeMap.Clear();

                // 验证Token并获取ClaimsPrincipal
                var principal = handler.ValidateToken(token, validationParameters, out _);
                return principal.Claims;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Token 解析失败: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 将 JWT 的 Claims 转换为 LoginUser 对象。
        /// </summary>
        /// <param name="jwtToken">JWT 中的 Claims 集合。</param>
        /// <returns>返回 LoginUser 对象，解析失败则返回 null。</returns>
        private static LoginUser ValidateJwtToken(IEnumerable<Claim> jwtToken)
        {
            try
            {
                // 输出 claims 到控制台
                Console.WriteLine("Parsed Claims:");
                foreach (var claim in jwtToken)
                {
                    Console.WriteLine($"Type: {claim.Type}, Value: {claim.Value}");
                }
                // 从 Claims 中提取关键字段（假设这些字段存在且格式正确）
                string primarySid = jwtToken.FirstOrDefault(c => c.Type == "primarysid")?.Value;
                string uniqueName = jwtToken.FirstOrDefault(c => c.Type == "unique_name")?.Value;
                // 使用实际存在的 Claim 类型 "UserData"
                string userDataJson = jwtToken.FirstOrDefault(c =>
                    c.Type == "UserData" ||  // 新格式
                    c.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata" // 旧格式
                )?.Value;

                // 反序列化 userdata 字段为 LoginUser 对象
                if (string.IsNullOrEmpty(userDataJson))
                    return null;

                return JsonConvert.DeserializeObject<LoginUser>(userDataJson);
            }
            catch (Exception ex)
            {
                // 记录异常日志（实际项目中建议使用日志框架）
                Console.WriteLine($"Claims 解析失败: {ex.Message}");
                return null;
            }
        }
    }

}
